module aru_unary_pow (
    input logic                        clk,
    input logic                        rst_n,
          aru_unary_cfg_if.no_clamp_in u_aru_cfg_if,
          aru_payload_if.in            u_aru_pld_left_if,
          aru_payload_if.out           u_aru_pld_right_if
);
    logic lst_req_in_instr;
    assign lst_req_in_instr = u_aru_pld_right_if.sdb.eom && u_aru_pld_right_if.sdb.eon;

    // cfg handshake
    logic cfg_rdy, cfg_vld;
    assign cfg_vld = ~cfg_rdy;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cfg_rdy <= 1'b1;
        end else if (cfg_rdy == 1'b0) begin
            if (u_aru_pld_right_if.vld && u_aru_pld_right_if.rdy && lst_req_in_instr) begin
                cfg_rdy <= 1'b1;
            end
        end else begin
            if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy) begin
                cfg_rdy <= 1'b0;
            end
        end
    end

    aru_dat_t exp_out;
    genvar i;
    logic pow_out_vld[`P_ARU * `N0 - 1:0];
    for (i = 0; i < `P_ARU * `N0; i = i + 1) begin : gen_pow
        bf16_fpmult u_bf16_fpmul (
            .clk         (clk),
            .rst         (!rst_n),
            .clock_enable(u_aru_pld_right_if.rdy && cfg_vld),
            .in_valid    (u_aru_pld_left_if.vld),
            .X           (u_aru_pld_left_if.dat.dat[i]),
            .Y           (u_aru_pld_left_if.dat.dat[i]),
            .R           (exp_out.dat[i]),
            .out_valid   (pow_out_vld[i])
        );
    end

    aru_dat_t delayed_dat;
    common_delay_line #(
        .WIDTH(`P_ARU * `N0 * $bits(bf16_t)),
        .DEPTH(`MUL_LATENCY - 1)
    ) u_data_delay_line (
        .clk  (clk),
        .rst_n(rst_n),
        .en   (u_aru_pld_right_if.rdy && cfg_vld),
        .data_in  (u_aru_pld_left_if.dat),
        .data_out (delayed_dat)
    );

    logic delayed_vld;
    common_delay_line #(
        .WIDTH(1),
        .DEPTH(`MUL_LATENCY - 1)
    ) u_valid_delay_line (
        .clk  (clk),
        .rst_n(rst_n),
        .en   (u_aru_pld_right_if.rdy && cfg_vld),
        .data_in  (u_aru_pld_left_if.vld),
        .data_out (delayed_vld)
    );

    aru_sdb_t delayed_sdb;
    common_delay_line #(
        .WIDTH($bits(aru_sdb_t)),
        .DEPTH(`MUL_LATENCY - 1)
    ) u_sdb_delay_line (
        .clk  (clk),
        .rst_n(rst_n),
        .en   (u_aru_pld_right_if.rdy && cfg_vld),
        .data_in  (u_aru_pld_left_if.sdb),
        .data_out (delayed_sdb)
    );

    assign u_aru_pld_left_if.rdy  = u_aru_pld_right_if.rdy && cfg_vld;
    assign u_aru_pld_right_if.vld = delayed_vld && cfg_vld;
    assign u_aru_pld_right_if.dat = u_aru_cfg_if.en ? exp_out : delayed_dat;
    assign u_aru_pld_right_if.sdb = delayed_sdb;

endmodule
